#include <stdio.h>

#include "../sjjg/stree.h"

#define _AUTO_TEST_

#ifdef _AUTO_TEST_
#define PRINT
#else
#define PRINT printf
#endif

size_t rbtree_balance(ms_rbtree_p t, ms_rbtree_p n, size_t d) {
    if (t == n) return d;
    if (MS_RBTREE_BLACK == n->color)
        ++d;
    else {
        if (n->left->color == MS_RBTREE_RED || n->right->color == MS_RBTREE_RED) {
            printf("rbtree red error\n");
        }
    }
    size_t ld = rbtree_balance(t, n->left, d);
    size_t rd = rbtree_balance(t, n->right, d);
    if (ld != rd) {
        printf("rbtree black error\n");
    }
    return ld;
}

bool less(void* left, void* right) {
    return (long)left < (long)right;
}
int getSel() {
    printf("1.add not repeatable\n");
    printf("2.add repeatable\n");
    printf("3.find all\n");
    printf("4.find one\n");
    printf("5.show map\n");
    printf("6.delete\n");
    printf("7.clear\n");
    printf("other exit\n");
    printf("select please:");
    int i;
    scanf("%d", &i);
    return i;
}
int getkey() {
    int key;
#ifdef _AUTO_TEST_
    key = rand()%10000;
#else
    printf("enter a key:");
    scanf("%d", &key);
#endif
    return key;
}

typedef struct map_pair_s {
    int key;
    int val;
}map_pair_t;

void map_pair_init(void* p) {
    memset(p, 0, sizeof(map_pair_t));
}

void map_pair_copy(void* dst, void* src) {
    memcpy(dst, src, sizeof(map_pair_t));
}
void* map_key(void* d) {
    return (void*)((map_pair_t*)d)->key;
}

bool map_less(void* l, void* r) {
    return (int)l < (int)r;
}

int main(int args, char* argv[]) {
    ms_stree_funs fs;
    memset(&fs, 0, sizeof(fs));
    fs.construct = map_pair_init;
    fs.copy = map_pair_copy;
    fs.key_fn = map_key;
    fs.key_cmp = map_less;
    size_t ct = 0;
    ms_stree map = ms_stree_create(NULL, sizeof(map_pair_t), &fs);
    do {
#ifdef _AUTO_TEST_
        int i = 0;
        if (ct % 2) {
            i = rand() % 9;
            switch (i)
            {
            case 0:
            case 1:
                i = 1;
                break;
            case 2:
            case 3:
                i = 2;
                break;
            case 4:
                if (ms_stree_size(map) < 8 * 1024 * 1024) {
                    i = 1;
                }
                else {
                    i = 6;
                }
                break;
            case 5:
            case 6:
            case 7:
            case 8:
                i = 6;
                break;
            default:
                break;
            }
            PRINT("!!!!!!select:%d\n", i);
        }
        else {
            i = 5;
        }
#else
        int i = getSel();
#endif
        switch (i) {
        case 1: {
            int key = getkey();
            int val = rand() % 10000;
            PRINT("value:%d\n", val);
            map_pair_t pt = { key, val };
            ms_stree_insert(map, &pt, false);
        }
                break;
        case 2: {
            int key = getkey();
            int val = rand() % 10000;
            PRINT("value:%d\n", val);
            map_pair_t pt = { key, val };
            ms_stree_insert(map, &pt, true);
        }
                break;
        case 3: {
            int key = getkey();
            ms_stree_node b = ms_stree_lower_bound(map, (void*)key);
            ms_stree_node e = ms_stree_upper_bound(map, (void*)key);
            if (b != e) {
                while (b != e) {
                    map_pair_t* v = (map_pair_t*)b->p;
                    printf("find:%d,%d\n", (int)v->key, (int)v->val);
                    b = ms_stree_next(map, b);
                }
            }
        }
                break;
        case 4: {
            int key = getkey();
            ms_stree_node i = ms_stree_find(map, (void*)key);
            if (i && i != ms_stree_end(map)) {
                map_pair_t* v = (map_pair_t*)i->p;
                printf("find:%d,%d\n", (int)v->key, (int)v->val);
            }
        }
                break;
        case 5: {
            size_t c = 0;
            ms_stree_node i = ms_stree_begin(map);
            int last_key = 0;
            while (i && ms_stree_end(map) != i) {
                map_pair_t* v = (map_pair_t*)i->p;
                if (map_less(v->key, last_key)) {
                    printf("sort error.%d > %d", last_key, v->key);
                    goto exit;
                }
                last_key = v->key;
                PRINT("find:%d,%d\n", (int)v->key, (int)v->val);
                i = ms_stree_next(map, i);
                ++c;
            }
            printf("size:%lu = %lu\n", c, ms_stree_size(map));
            if (c != ms_stree_size(map)) {
                goto exit;
            }
            rbtree_balance(map->sentinel, map->sentinel->parent, 0);
        }
                break;
        case 6:
            if (!ms_stree_empty(map)){
#ifdef _AUTO_TEST_
                int key = rand()%ms_stree_size(map);
                ms_stree_node i = ms_stree_begin(map);
                int last_key = 0;
                while (key >= 0 && i && ms_stree_end(map) != i) {
                    map_pair_t* v = (map_pair_t*)i->p;
                    if (map_less(v->key, last_key)) {
                        printf("sort error.%d > %d", last_key, v->key);
                        goto exit;
                    }
                    last_key = v->key;
                    i = ms_stree_next(map, i);
                    --key;
                }
                key = last_key;
#else
                int key = getkey();
#endif
                ms_stree_node item = ms_stree_find(map, (void*)key);
                if (item) {
                    ms_stree_remove(map, item);
                }
            }
            break;
        case 7: {
            ms_stree_clear(map);
            printf("map size:%lu\n", ms_stree_size(map));
        }
            break;
        default:
            goto exit;
        }
    } while (++ct < 987654321);
exit:
    ms_stree_destory(map);
    return 0;
}

